// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mac

import (
	"go.thethings.network/lorawan-stack/v3/pkg/band"
	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
)

// CFList generated by this frequency plan, for the version used by a device.
// This function returns nil if the CFList could not be computed, or if the
// device does not support CFLists.
func CFList(phy *band.Band, channels ...*ttnpb.MACParameters_Channel) *ttnpb.CFList {
	if !phy.ImplementsCFList {
		return nil
	}

	switch phy.CFListType {
	case ttnpb.CFListType_CHANNEL_MASKS:
		return chMaskCFList(phy, channels...)
	case ttnpb.CFListType_FREQUENCIES:
		return frequenciesCFList(phy, channels...)
	default:
		return nil
	}
}

func chMaskCFList(phy *band.Band, channels ...*ttnpb.MACParameters_Channel) *ttnpb.CFList {
	chMasks := make([]bool, len(phy.UplinkChannels))
outer:
	for i, bandChannel := range phy.UplinkChannels {
		for _, ch := range channels {
			if !ch.EnableUplink {
				continue
			}
			if ch.UplinkFrequency == bandChannel.Frequency {
				chMasks[i] = true
				continue outer
			}
		}
	}
	return &ttnpb.CFList{
		Type:    ttnpb.CFListType_CHANNEL_MASKS,
		ChMasks: chMasks[:],
	}
}

func frequenciesCFList(phy *band.Band, channels ...*ttnpb.MACParameters_Channel) *ttnpb.CFList {
	freqs := make([]uint32, 0, 5)
outer:
	for _, ch := range channels {
		if !ch.EnableUplink {
			continue
		}
		for _, bandChannel := range phy.UplinkChannels {
			if ch.UplinkFrequency == bandChannel.Frequency {
				continue outer
			}
		}
		freqs = append(freqs, uint32(ch.UplinkFrequency/phy.FreqMultiplier))
		if len(freqs) == 5 {
			break
		}
	}
	return &ttnpb.CFList{
		Type: ttnpb.CFListType_FREQUENCIES,
		Freq: freqs,
	}
}
